home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / EventListenerList.java < prev    next >
Text File  |  1998-06-30  |  8KB  |  254 lines

  1. /*
  2.  * @(#)EventListenerList.java    1.18 98/02/02
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.event;
  21.  
  22. import java.io.*;
  23. import java.util.*;
  24.  
  25. /**
  26.  * A class which holds a list of EventListeners.  A single instance
  27.  * can be used to hold all listeners (of all types) for the instance
  28.  * using the lsit.  It is the responsiblity of the class using the
  29.  * EventListenerList to provide type-safe API (preferably conforming
  30.  * to the JavaBeans spec) and methods which dispatch event notification
  31.  * methods to appropriate Event Listeners on the list.
  32.  * 
  33.  * The main benefits which this class provides are that it is relatively
  34.  * cheap in the case of no listeners, and provides serialization for 
  35.  * eventlistener lists in a single place, as well as a degree of MT safety
  36.  * (when used correctly).
  37.  *
  38.  * Usage example:
  39.  *    Say one is defining a class which sends out FooEvents, and wantds
  40.  * to allow users of the class to register FooListeners and receive 
  41.  * notification when FooEvents occur.  The following should be added
  42.  * to the class definition:
  43.    <pre>
  44.    EventListenerList listenrList = new EventListnerList();
  45.    FooEvent fooEvent = null;
  46.  
  47.    public void addFooListener(FooListener l) {
  48.        listenerList.add(FooListener.class, l);
  49.    }
  50.  
  51.    public void removeFooListener(FooListener l) {
  52.        listenerList.remove(FooListener.class, l);
  53.    }
  54.  
  55.  
  56.     // Notify all listeners that have registered interest for
  57.     // notification on this event type.  The event instance 
  58.     // is lazily created using the parameters passed into 
  59.     // the fire method.
  60.  
  61.     protected void firefooXXX() {
  62.     // Guaranteed to return a non-null array
  63.     Object[] listeners = listenerList.getListenerList();
  64.     // Process the listeners last to first, notifying
  65.     // those that are interested in this event
  66.     for (int i = listeners.length-2; i>=0; i-=2) {
  67.         if (listeners[i]==FooListener.class) {
  68.         // Lazily create the event:
  69.         if (fooEvent == null)
  70.             fooEvent = new FooEvent(this);
  71.         ((FooListener)listeners[i+1]).fooXXX(fooEvent);
  72.         }           
  73.     }
  74.     }    
  75.    </pre>
  76.  * foo should be changed to the appropriate name, and Method to the
  77.  * appropriate method name (one fire method should exist for each
  78.  * notification method in the FooListener interface).
  79.  * <p>
  80.  * Warning: serialized objects of this class will not be compatible with
  81.  * future swing releases.  The current serialization support is appropriate 
  82.  * for short term storage or RMI between Swing1.0 applications.  It will
  83.  * not be possible to load serialized Swing1.0 objects with future releases
  84.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  85.  * baseline for the serialized form of Swing objects.
  86.  *
  87.  * @version 1.18 02/02/98
  88.  * @author Georges Saab
  89.  * @author Hans Muller
  90.  * @author James Gosling
  91.  */
  92. public class EventListenerList implements Serializable {
  93.     /* A null array to be shared by all empty listener lists*/
  94.     private final static Object[] NULL_ARRAY = new Object[0];
  95.     /* The list of ListenerType - Listener pairs */
  96.     protected transient Object[] listenerList = NULL_ARRAY;
  97.  
  98.     /**
  99.      * This passes back the event listener list as an array
  100.      * of ListenerType - listener pairs.  Note that for 
  101.      * performance reasons, this implementation passes back 
  102.      * the actual data structure in which the listner data
  103.      * is stored internally!  
  104.      * This method is guaranteed to pass back a non-null
  105.      * array, so that no null-checking is required in 
  106.      * fire methods.  A zero-length array of Object should
  107.      * be returned if there are currently no listeners.
  108.      * 
  109.      * WARNING!!! Absolutely NO modification of
  110.      * the data contained in this array should be made -- if
  111.      * any such manipulation is necessary, it should be done
  112.      * on a copy of the array returned rather than the array 
  113.      * itself.
  114.      */
  115.     public Object[] getListenerList() {
  116.     return listenerList;
  117.     }
  118.  
  119.     /**
  120.      * Return the total number of listeners for this listenerlist
  121.      */
  122.     public int getListenerCount() {
  123.     return listenerList.length/2;
  124.     }
  125.  
  126.     /**
  127.      * Return the total number of listeners of the supplied type 
  128.      * for this listenerlist.
  129.      */
  130.     public int getListenerCount(Class t) {
  131.     int count = 0;
  132.     Object[] lList = listenerList;
  133.     for (int i = 0; i < lList.length; i+=2) {
  134.         if (t == (Class)lList[i])
  135.         count++;
  136.     }
  137.     return count;
  138.     }
  139.     /**
  140.      * Add the listener as a listener of the specified type.
  141.      * @param t the type of the listener to be added
  142.      * @param l the listener to be added
  143.      */
  144.     public synchronized void add(Class t, EventListener l) {
  145.     if (!t.isInstance(l)) {
  146.         throw new IllegalArgumentException("Listener " + l +
  147.                      " is not of type " + t);
  148.     }
  149.     if (l ==null) {
  150.         throw new IllegalArgumentException("Listener " + l +
  151.                      " is null");
  152.     }
  153.     if (listenerList == NULL_ARRAY) {
  154.         // if this is the first listener added, 
  155.         // initialize the lists
  156.         listenerList = new Object[] { t, l };
  157.     } else {
  158.         // Otherwise copy the array and add the new listener
  159.         int i = listenerList.length;
  160.         Object[] tmp = new Object[i+2];
  161.         System.arraycopy(listenerList, 0, tmp, 0, i);
  162.  
  163.         tmp[i] = t;
  164.         tmp[i+1] = l;
  165.  
  166.         listenerList = tmp;
  167.     }
  168.     }
  169.  
  170.     /**
  171.      * Remove the listener as a listener of the specified type.
  172.      * @param t the type of the listener to be removed
  173.      * @param l the listener to be removed
  174.      */
  175.     public synchronized void remove(Class t, EventListener l) {
  176.     if (!t.isInstance(l)) {
  177.         throw new IllegalArgumentException("Listener " + l +
  178.                      " is not of type " + t);
  179.     }
  180.     if (l ==null) {
  181.         throw new IllegalArgumentException("Listener " + l +
  182.                      " is null");
  183.     }
  184.  
  185.     // Is l on the list?
  186.     int index = -1;
  187.     for (int i = listenerList.length-2; i>=0; i-=2) {
  188.         if ((listenerList[i]==t) && (listenerList[i+1] == l)) {
  189.         index = i;
  190.         break;
  191.         }
  192.     }
  193.     
  194.     // If so,  remove it
  195.     if (index != -1) {
  196.         Object[] tmp = new Object[listenerList.length-2];
  197.         // Copy the list up to index
  198.         System.arraycopy(listenerList, 0, tmp, 0, index);
  199.         // Copy from two past the index, up to
  200.         // the end of tmp (which is two elements
  201.         // shorter than the old list)
  202.         if (index < tmp.length)
  203.         System.arraycopy(listenerList, index+2, tmp, index, 
  204.                  tmp.length - index);
  205.         // set the listener array to the new array or null
  206.         listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;
  207.         }
  208.     }
  209.  
  210.     // Serialization support.  
  211.     private void writeObject(ObjectOutputStream s) throws IOException {
  212.     Object[] lList = listenerList;
  213.     s.defaultWriteObject();
  214.     
  215.     // Save the non-null event listeners:
  216.     for (int i = 0; i < lList.length; i+=2) {
  217.         Class t = (Class)lList[i];
  218.         EventListener l = (EventListener)lList[i+1];
  219.         if ((l!=null) && (l instanceof Serializable)) {
  220.         s.writeObject(t.getName());
  221.         s.writeObject(l);
  222.         }
  223.     }
  224.     
  225.     s.writeObject(null);
  226.     }
  227.  
  228.     private void readObject(ObjectInputStream s) 
  229.     throws IOException, ClassNotFoundException {
  230.         listenerList = NULL_ARRAY;
  231.     s.defaultReadObject();
  232.     Object listenerTypeOrNull;
  233.     
  234.     while (null != (listenerTypeOrNull = s.readObject())) {
  235.         EventListener l = (EventListener)s.readObject();
  236.         add(Class.forName((String)listenerTypeOrNull), l);
  237.     }        
  238.     }
  239.  
  240.     /**
  241.      * Return a string representation of the EventListenerList.
  242.      */
  243.     public String toString() {
  244.     Object[] lList = listenerList;
  245.     String s = "EventListenerList: ";
  246.     s += lList.length/2 + " listeners: ";
  247.     for (int i = 0 ; i <= lList.length-2 ; i+=2) {
  248.         s += " type " + ((Class)lList[i]).getName();
  249.         s += " listener " + lList[i+1];
  250.     }
  251.     return s;
  252.     }
  253. }
  254.